﻿/* cpcPaChi;

   Un compilador de Pascal chiquitito para CPC
   Por Nacho Cabanes - Version en C#

   Clase "TablaSimbolos" (tabla de símbolos)

   Versiones hasta la fecha:

   Num.    Fecha       Cambios
   ---------------------------------------------------
   0.15cs  01-Dic-2010  Añadida la posibilidad de depurar para ver
                        lo que se introduce y lo que sale
                        (corrige la dirección, que podía ser incorrecta
                        al introducir un LABEL)
   0.14cs  17-Nov-2010  Se puede insertar procedimientos (PROCEDURE)
   0.11cs  08-Nov-2010  Se puede insertar etiquetas (LABEL) para saltos
                        y cambiar el valor/direccion de un símbolo
                        Añadido GetNumSimbolos y GetSimbolo(i) para
                        ayudar en la segunda pasada
   0.10cs  06-Nov-2010  Se puede guargar variables, y se les asigna
                        una dirección de memoria creciente
   0.09cs  04-Nov-2010  Añadido "ExisteSimbolo", para ver
                        si una variable ya se ha declarado
   0.07cs  31-Oct-2010  Primera versión, con capacidad para 1000
                        símbolos; permite insertar constantes
                        y leerlas

*/

using System;

public enum tamDato { BYTE, INTEGER };
public enum tipoId { INEXIST, CONST, VAR, LABEL, PROCEDURE };

public class TablaSimbolos
{

  struct tipoSimbolo
  {
    public string nombre;
    public tipoId tipo;
    public tamDato tamanyo;
    public int valorDir;
  }

  tipoSimbolo[] listaSimbolos;
  const int MAXSIMBOLOS = 100;
  int numSimbolos;
  int ultimaDireccion = 40000;
  bool depurando = false;


  // Constructor: reserva espacio
  public TablaSimbolos()
  {
    listaSimbolos = new tipoSimbolo[MAXSIMBOLOS];
    numSimbolos = 0;
  }


  // Indicar la dirección de comienzo de las posiciones
  // de memoria que usarán las variables
  public void IndicarComienzo(int pos)
  {
    ultimaDireccion = pos;
  }


  // Guardar una constante o variable en la tabla de símbolos
  public void Insertar(string nombre, tipoId tipo,
    tamDato tamanyo, int valorDir)
  {
    if (depurando)
      Console.WriteLine("Insertando: {0} , {1} , {2} , {3} ",
        nombre, tipo, tamanyo, valorDir);

    nombre = nombre.ToUpper();
    // Primero comprobamos si el simbolo ya existe
    for (int i=0; i < MAXSIMBOLOS; i++)
      if (listaSimbolos[i].nombre == nombre)
      {
        Console.WriteLine("Identificador ya definido: {0}", nombre);
        Environment.Exit(1);
      }

    // Si no existe (y cabe), lo insertamos
    if (numSimbolos >= MAXSIMBOLOS - 1)
    {
        Console.WriteLine("Tabla de símbolos llena!");
        Environment.Exit(1);
    }

    listaSimbolos[numSimbolos].nombre = nombre;
    listaSimbolos[numSimbolos].tamanyo = tamanyo;
    listaSimbolos[numSimbolos].tipo = tipo;
    if ( tipo == tipoId.CONST)  // Constante: guardo valor
      listaSimbolos[numSimbolos].valorDir = valorDir;
    else if ( tipo == tipoId.LABEL)  // Label: guardo valor
      listaSimbolos[numSimbolos].valorDir = valorDir;
    else if ( tipo == tipoId.PROCEDURE)  // Procedure: idem
      listaSimbolos[numSimbolos].valorDir = valorDir;
    else if ( tipo == tipoId.VAR) // Variable: en la siguiente posición
    {
      listaSimbolos[numSimbolos].valorDir = ultimaDireccion;
      ultimaDireccion ++; // Incremento en 1 byte, para tipo byte
    }
    numSimbolos++;
    //############
  }


  // Leer una constante de la tabla de símbolos
  public int LeerValor(string nombre)
  {
    nombre = nombre.ToUpper();
    // Primero comprobamos si el simbolo ya existe
    for (int i=0; i < MAXSIMBOLOS; i++)
      if (listaSimbolos[i].nombre == nombre)
      {
        if (depurando)
          Console.WriteLine("Leyendo: {0} , {1}",
            nombre, listaSimbolos[i].valorDir);
        return listaSimbolos[i].valorDir;
      }
    // Si no se ha devuelto valor es que no existe
    Console.WriteLine("Identificador inexistente: {0}", nombre);
    Environment.Exit(1);
    return 0;  // (No se llega nunca; necesario para que compile)
  }


  // Leer un valor o una constante numérica con nombre
  public int LeerValorOConst(string cadenaTemp)
  {
    if ( (cadenaTemp[0] >= '0') && (cadenaTemp[0] <= '9'))
      return Convert.ToInt32( cadenaTemp );
    else
      return LeerValor(cadenaTemp);
  }


  // Devuelve el tipo de un identificador (o INEXIST si
  // no aparece en la tabla)
  public tipoId LeerTipo(string identif)
  {
    tipoId tipoReal = tipoId.INEXIST;
    for (int i=0; i < numSimbolos; i++)
      if (listaSimbolos[i].nombre.ToUpper() == identif.ToUpper() )
        tipoReal = listaSimbolos[i].tipo;
    return tipoReal;
  }

  // Guardar una constante o variable en la tabla de símbolos
  public void CambiarValor(string nombre, int nuevoValor)
  {
    nombre = nombre.ToUpper();
    bool encontrado = false;
    // Primero comprobamos si el simbolo ya existe
    for (int i=0; i < MAXSIMBOLOS; i++)
      if (listaSimbolos[i].nombre == nombre)
      {
        if (depurando)
          Console.WriteLine("Cambiando: {0} , {1}",
            nombre, nuevoValor);
        listaSimbolos[i].valorDir = nuevoValor;
        encontrado = true;
      }
    if ( ! encontrado )
    {
      Console.WriteLine("Identificador inexistente: {0}", nombre);
      Environment.Exit(1);
    }
  }

  // Devuelve la cantidad de simbolos
  public int GetNumSimbolos()
  {
    return numSimbolos;
  }

  // Devuelve el simbolo que hay en una cierta posicion
  public string GetSimbolo(int i)
  {
    return listaSimbolos[i].nombre;
  }

  // Devuelve el valor (o direccion) que hay en una cierta posicion
  public int GetValor(int i)
  {
    return listaSimbolos[i].valorDir;
  }


}
